package com.countertack.vmware;

import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.HashMap;

import org.doublecloud.vi.vmware.guest.GuestProcessDirector;

import com.countertack.utils.Configuration;
import com.vmware.vim25.FileFault;
import com.vmware.vim25.GuestProgramSpec;
import com.vmware.vim25.InsufficientResourcesFault;
import com.vmware.vim25.InvalidProperty;
import com.vmware.vim25.InvalidState;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.NamePasswordAuthentication;
import com.vmware.vim25.RuntimeFault;
import com.vmware.vim25.TaskInProgress;
import com.vmware.vim25.VirtualMachineSnapshotTree;
import com.vmware.vim25.VmConfigFault;
import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.GuestAuthManager;
import com.vmware.vim25.mo.GuestOperationsManager;
import com.vmware.vim25.mo.GuestProcessManager;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;
import com.vmware.vim25.mo.VirtualMachineSnapshot;

public class VMWareConnector {

	ServiceInstance si = null;
	HashMap<String, VirtualMachine> vmList;

	String esxihost;

	public boolean reconnectToEsxi() {
		vmList = new HashMap<String, VirtualMachine>();
		boolean reconStatus = false;
		try {

			si = new ServiceInstance(new URL("https://" + esxihost + "/sdk"),
					"root", "f00009999b@@@@r", true);

			Folder rootFolder = si.getRootFolder();

			ManagedEntity[] entites = new InventoryNavigator(rootFolder)
					.searchManagedEntities("VirtualMachine");
			for (ManagedEntity me : entites) {

				VirtualMachine vm = (VirtualMachine) me;

				if (vm != null) {
					String vname = vm.getConfig().name;

					vmList.put(vname, vm);

				}
			}
			reconStatus = true;

		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			System.out.println("failed to connect to esxi");
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			System.out.println("failed to connect to esxi");
			e.printStackTrace();
		} catch (Exception e) {

			System.out.println("failed to connect to esxi");
			e.printStackTrace();
		} finally {
			return reconStatus;
		}

	}

	public VMWareConnector(String esxiHost) {
		this.esxihost = esxiHost;
		vmList = new HashMap<String, VirtualMachine>();
		try {
			si = new ServiceInstance(new URL("https://" + esxiHost + "/sdk"),
					"root", "f00009999b@@@@r", true);

			Folder rootFolder = si.getRootFolder();

			ManagedEntity[] entites = new InventoryNavigator(rootFolder)
					.searchManagedEntities("VirtualMachine");
			for (ManagedEntity me : entites) {

				VirtualMachine vm = (VirtualMachine) me;

				if (vm != null) {
					String vname = vm.getConfig().name;

					vmList.put(vname, vm);

				}
			}

		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			System.out.println("failed to connect to esxi");
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			System.out.println("failed to connect to esxi");
			e.printStackTrace();
		} catch (Exception e) {

			System.out.println("failed to connect to esxi");
			e.printStackTrace();
		}

	}

	public void startVirtualMachine(VirtualMachine vm) {

		try {

			if (vm != null) {

				if (!"poweredOn".equalsIgnoreCase(vm.getRuntime().powerState
						.name())) {

					Task pwrOnTask = vm.powerOnVM_Task(null);
					pwrOnTask.waitForTask();

				} else {

					vm.rebootGuest();

				}

			}

		} catch (Exception e) {

			e.printStackTrace();

			System.out.println("Exception in starting virtual machine");

		}

	}

	public void checkAndRunVirtualMachine(VirtualMachine vm) {
		boolean startFlag = false;
		try {
			String virtualMachineStatus = getVirtualMachineStatus(vm);

			if (virtualMachineStatus == null) {
				startFlag = true;
				startVirtualMachine(vm);

			} else {

				if ("notRunning".equalsIgnoreCase(virtualMachineStatus)) {
					startFlag = true;
					reStartVirtualMachine(vm);

				}

			}

			while (true) {

				if ("guestToolsRunning"
						.equalsIgnoreCase(vm.getGuest().toolsRunningStatus)) {
					if (startFlag) {

						Thread.sleep(120000);

					}

					break;

				}

				Thread.sleep(30000);
			}

		} catch (Exception e) {

			e.printStackTrace();

		}

	}

	public void hibernateVirtualMachine(VirtualMachine vm, String vmUser,
			String vmPassword ) {

		try {

			if ("guestToolsRunning"
					.equalsIgnoreCase(vm.getGuest().toolsRunningStatus)) {
				try {
					
					
					boolean isXp=false;
					String osType = VMWareUtils.getVMOSArchitecture(
							Configuration.getProperty("esxi"),
							Configuration.getProperty("vmname"));
					
					if (osType != null) {

						osType = osType.toLowerCase();

						if (osType.contains("xp")) {

							isXp = true;
						}
					}

					GuestProcessDirector progDir = new GuestProcessDirector(vm,
							vmUser, vmPassword);

					try {

						GuestAuthManager gam = getOperationManager()
								.getAuthManager(vm);
						NamePasswordAuthentication npa = new NamePasswordAuthentication();
						npa.username = vmUser;
						npa.password = vmPassword;

						GuestProgramSpec spec = new GuestProgramSpec();
						spec.programPath = "C:\\Windows\\System32\\powercfg.exe";
						spec.arguments = "hibernate on";

						GuestProcessManager gpm = getOperationManager()
								.getProcessManager(vm);
						long pid = gpm.startProgramInGuest(npa, spec);
						System.out.println("pid>>"+pid);
						Thread.sleep(60000);
					} catch (Exception e) {

						e.printStackTrace();
					}
					try {
						
						if(isXp){
							
							GuestAuthManager hgam = getOperationManager()
									.getAuthManager(vm);
							NamePasswordAuthentication hnpa = new NamePasswordAuthentication();
							hnpa.username = vmUser;
							hnpa.password = vmPassword;

							GuestProgramSpec hspec = new GuestProgramSpec();
							hspec.programPath = "C:\\Windows\\System32\\rundll32.exe";
							hspec.arguments = "powrprof.dll,SetSuspendState";
							 

							GuestProcessManager hgpm = getOperationManager()
									.getProcessManager(vm);
							long pid = hgpm.startProgramInGuest(hnpa, hspec);
							System.out.println("pid>>"+pid);
							
						}
						else{
							progDir.run("C:\\Windows\\System32\\cmd.exe",
									"/c shutdown /h");
							
						}
						
						Thread.sleep(30000);
						String virtualMachineStatus = getVirtualMachineStatus(vm);

						while (true) {

							if (virtualMachineStatus == null
									|| "notRunning"
											.equalsIgnoreCase(virtualMachineStatus)) {

								break;

							}
							virtualMachineStatus = getVirtualMachineStatus(vm);

						}

						System.out.println("Hibernate done!!!");

					} catch (Exception e) {
						e.printStackTrace();

					}

				} catch (Exception e) {

					e.printStackTrace();
				}

			}

		} catch (Exception e) {

			e.printStackTrace();

		}

	}

	public void reStartVirtualMachine(VirtualMachine vm) {

		try {

			if (vm != null) {
				if (!"poweredOn".equalsIgnoreCase(vm.getRuntime().powerState
						.name())) {

					vm.powerOnVM_Task(null);

				} else {
					vm.rebootGuest();

				}

			}

		} catch (Exception e) {

			e.printStackTrace();

			System.out.println("Exception in starting virtual machine");

		}

	}

	public VirtualMachine getVirtualMachineByname(String vmName) {

		if (vmList != null) {

			return vmList.get(vmName);
		}

		return null;

	}

	public String getVirtualMachineStatus(VirtualMachine vm) {

		if (vm != null) {

			if (vm.getGuest() != null) {

				return vm.getGuest().getGuestState();

			}

		}

		return null;

	}

	public void createSnapShot(VirtualMachine vm, String snapShotName,
			String description) {

		try {

			Task task = vm.createSnapshot_Task(snapShotName, description,
					false /* memory */, true /* quiesce */);
			try {
				task.waitForTask();
				System.out.println("Create snapshot result>>>>>>"
						+ task.getTaskInfo().getResult());
				Thread.sleep(300000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (InvalidProperty e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RuntimeFault e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void revertToSnapShort(
			VirtualMachineSnapshotTree[] rootSnapshotList, String snapShotName) {
		if (rootSnapshotList != null) {
			for (int i = 0; i < rootSnapshotList.length; i++) {
				VirtualMachineSnapshotTree snapshotTree = rootSnapshotList[i];
				String name = snapshotTree.getName();

				if (name.equals(snapShotName)) {

					VirtualMachineSnapshot snapshot = new VirtualMachineSnapshot(
							si.getServerConnection(),
							snapshotTree.getSnapshot());
					try {
						Task revertTask = snapshot.revertToSnapshot_Task(null);

						revertTask.waitForTask();
						System.out.println("Revert result>>>>>>"
								+ revertTask.getTaskInfo().getResult());
						Thread.sleep(300000);

						break;

					} catch (Exception e) {

						e.printStackTrace();
						break;
					}
				} else {
					revertToSnapShort(snapshotTree.childSnapshotList,
							snapShotName);
				}

			}
		}
	}

	public GuestOperationsManager getOperationManager() {

		if (si != null) {

			return si.getGuestOperationsManager();

		}
		return null;

	}

	public void closeEsxiConnection() {

		try {
			if (si != null) {

				si.getServerConnection().logout();

			}
		} catch (Exception e) {

			e.printStackTrace();
		}

	}

}
